package application.adapter;

import application.anno.Column;
import javafx.collections.ObservableList;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class TableAdapter<T> {

    private TableView<T> tableView;

    public TableAdapter(TableView<T> tableView) {
        this.tableView = tableView;
        init();
    }

    public void init() {
        Column annotation = this.getClass().getAnnotation(Column.class);
        if (annotation == null || annotation.columns().length <= 0) {
            return;
        }
        String[] columns = annotation.columns();
        for (String column : columns) {
            tableView.getColumns().add(new TableColumn<>(column));
        }
    }

    public void init(String[] columns) {
        if (columns == null || columns.length <= 0) {
            return;
        }
        for (String column : columns) {
            tableView.getColumns().add(new TableColumn<>(column));
        }
    }

    public void bindWidthToTableView(Class<T> cls) {
        Field[] declaredFields = cls.getDeclaredFields();
        ObservableList<TableColumn<T, ?>> columns = tableView.getColumns();
        for (TableColumn<T, ?> column : columns) {
            for (Field field : declaredFields) {
                Column annotation = field.getAnnotation(Column.class);
                if (column.getText().equals(annotation.filedName())) {
                    if (annotation.widthProportion() >= 0) {
                        column.prefWidthProperty().bind(tableView.widthProperty().multiply(annotation.widthProportion()));
                        break;
                    }
                    break;
                }
            }
        }
    }

    public void init(List<String> columns) {
        if (columns == null || columns.isEmpty()) {
            return;
        }
        for (String column : columns) {
            tableView.getColumns().add(new TableColumn<>(column));
        }
    }

    public void setItems(T[] ts) {
        for (T t : ts) {
            try {
                setItem(t);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    public void setItems(List<T> ts) {
        for (T t : ts) {
            try {
                setItem(t);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    protected void setItem(T t) throws IllegalAccessException {
        Column declaredAnnotation = this.getClass().getDeclaredAnnotation(Column.class);
        if (declaredAnnotation == null || declaredAnnotation.columns().length <= 0) {
            return;
        }
        // 当表的列名与对象的字段名不同时，Column注解应该将映射信息，填入filedName中，顺序应该与columnNames一直。
        Map<String, String> mapping = null;
        String[] columnNames = declaredAnnotation.columns();
        List<Field> fields = Arrays.asList(t.getClass().getDeclaredFields());
        fields.addAll(Arrays.asList(t.getClass().getSuperclass().getDeclaredFields()));
        if (fields.size() > 0) {
            mapping = new HashMap<>();
            for (Field field : fields) {
                Column annotation = field.getAnnotation(Column.class);
                if (annotation == null){
                    continue;
                }
                mapping.put(annotation.filedName(), field.getName());
            }
        }
        ObservableList<TableColumn<T, ?>> columns = tableView.getColumns();
        for (TableColumn<T, ?> tableColumn : columns) {
            tableColumn.setCellValueFactory(new PropertyValueFactory<>(mapping == null ? tableColumn.getText() : mapping.get(tableColumn.getText())));
        }
        tableView.getItems().add(t);
    }

}
